iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Software Development

Haskell 從入門到放棄系列 第 27

[Haskell 從入門到放棄] Day 27 - newtype

  • 分享至 

  • xImage
  •  

newtype

大概在之前的 monoid 的時候有提到過這個語法。

getProduct $ Product 1 `mappend` Product 2  `mappend` Product 3 -- 6

那時候我們說就類似取值的概念,那之所以 Product 會需要用 getProduct 來取值正是因為它使用了 newtype 來定義這個 type

newtype Product a = Product {getProduct :: a}

長得跟我們在使用 data type 的 record syntax 時很像,只是差異是 newtype 只能有一個 value constructor 且裡面也只能有一個 field 。

newtype IntList = IntList {getIntList:: [Int]} deriving (Eq, Show)
data IntList' = IntList' {getIntList':: [Int]} deriving (Eq, Show)

print $ IntList [1,2,3]  -- IntList {getIntList = [1,2,3]}
print $ IntList' [1,2,3]  -- IntList' {getIntList' = [1,2,3]}
print $ getIntList $ IntList [1,2,3]   -- [1,2,3]
print $ getIntList' $ IntList' [1,2,3]  -- [1,2,3]
print $ tail $ getIntList $ IntList [1,2,3]  -- [2,3]
print $ head $ getIntList $ IntList [1,2,3]  -- 1

當然我也可以替 newtype 所定義的 type 讓他成為其他 typeclass 的 instance

newtype IntWrapper = IntWrapper Int deriving (Eq, Show)

instance Semigroup IntWrapper where
    (IntWrapper a) <> (IntWrapper b) = IntWrapper (a + b)

instance Monoid IntWrapper where
    mempty = IntWrapper 0

print $ IntWrapper 1 <> IntWrapper 2 <> IntWrapper 3   -- IntWrapper 6
print $ mconcat [IntWrapper 1, IntWrapper 2, IntWrapper 3]  -- IntWrapper 6

這邊我們實作了 IntWrapper 作為 MonoidSemigroup 的 instance 的實作,經過這些實作我們就可以不用特地使用 pattern matching 來拆開 context 計算值。

所以 newtype 解決了什麼事情?基本上 newtype 是方便我們復用相似結構的 type 像是三角形的邊長以及三維座標一樣他們結構很像但實際上他們代表的意義完全不一樣,這也是為什麼它只有一個 value constructor 及 field 因為本意上就是想要讓開發者重新包裝一個 type 。


hmmm 今天突然想不到有什麼能寫所以只好挑一個有稍微提到但沒解釋過的語法來寫XD

今天的程式碼
https://github.com/toddLiao469469/30days-for-haskell


上一篇
[Haskell 從入門到放棄] Day 26 - Monad (4)
下一篇
[Haskell 從入門到放棄] Day 27 - Monad (5)
系列文
Haskell 從入門到放棄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
shootingstar
iT邦新手 4 級 ‧ 2023-10-10 09:01:56

請問老師~

既然newtype可以拿來包裝某個既有的type,那這樣為什麼不直接用data就好了?

newtype限制還一大堆,什麼只能有一個value constructor、一個filed的。

大大才真的算是老師吧 XD

不太確定我理解的對不對,但我想應該是因為 newtype 它的型別安全其實只有在編譯時才作用,這也讓他在 runtime 時可以比 data 快一點。
所以如果只是為了型別封裝之類的理由感覺就用 newtype 就好

題外話,我一直覺得 newtype 這個命名我蠻不能接受的,因為就語意上它更像是新建一個 type 而不是只在編譯時生效,然後 runtime 就變回基礎型別的感覺。

我要留言

立即登入留言